import { _decorator, Animation, AnimationClip, AnimationState, BoxCollider, Button, ButtonComponent, Camera, Component, Enum, Event, EventHandler, EventTouch, geometry, input, Input, instantiate, Label, Material, math, MeshRenderer, ModelComponent, Node, NodeEventType, ParticleAsset, ParticleSystem, PhysicsSystem, Prefab, quat, Quat, RigidBody, tween, v3, Vec3, Vec4 } from 'cc';
import { dialogController } from './dialogController';
import { bulletController } from './bulletController';
import { bloodController } from './bloodController';
const { ccclass, property } = _decorator;

enum gameStatus {
    STOP,
    RUN
}
@ccclass('gameManger')
export class gameManger extends Component {
    @property(Node) menu: Node // 开始游戏菜单
    @property(Camera) camera: Camera // 主相机
    @property(Node) gun: Node // 枪节点
    @property(Node) devil: Node // 恶魔npc节点
    @property(dialogController) dialog: dialogController // 情节对话框
    @property(bulletController) bullet: bulletController // 子弹控制类
    @property(Prefab) bulletPrefab: Prefab // 子弹模型资源预览节点
    @property(Node) shootMenu: Node // 选择射击菜单
    @property(bloodController) blood: bloodController // 血量控制类
    @property(Prefab) prop: Prefab; // 道具节点
    @property(Material) red: Material // 双倍伤害
    @property(Material) orange: Material // 查看下一个子弹
    @property(Material) blue: Material // 弹出下一个子弹
    @property(Material) grey: Material // 禁止一回合
    @property(Material) green: Material // 加血
    @property(Node) propsYouGroup: Node // 玩家的道具属性组
    @property(Node) propsNpcGroup: Node // npc的道具属性组
    @property(Node) stopTag: Node // 跳过回合标志
    @property(Material) bulletRed: Material // 子弹材质
    @property(Material) bulletBlue: Material // 子弹材质
    private animation: Animation = null // 主相机动画组件
    private bulletAry: Array<any> = [] // 子弹数组
    private haveGun: string = "you" // 当前控制枪的角色
    private round: number = 0 // 回合数
    private propsForYou: Array<Node> = [null, null, null, null, null, null] // 玩家的道具集合
    private propsForNpc: Array<Node> = [null, null, null, null, null, null] // npc的道具集合
    private postionAry: Array<Vec3> = [
        new Vec3(-0.5, 0.15, -0.25),
        new Vec3(0.5, 0.15, 0.25),
        new Vec3(-0.5, 0.15, 0.25),
        new Vec3(0.5, 0.15, -0.25),
        new Vec3(0, 0.15, 0.25),
        new Vec3(0, 0.15, -0.25),
    ] // 道具位置属性
    private _ray: geometry.Ray = new geometry.Ray();
    private doubleDamage: Boolean = false; // 是否开启双倍伤害
    private stopRound: Boolean = false // 是否有跳过回合

    start() {
        // this.gun.active = false
        // this.dialogLabel = this.dialog.getChildByPath("SpriteSplash/Label")
        // this.dialogLabel = this.dialog.getChildByPath("Label")
        this.animation = this.camera.getComponent(Animation)
    }
    onEnable() {
        input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
    }

    onDisable() {
        input.off(Input.EventType.TOUCH_START, this.onTouchStart, this);
    }
    /**
     * 道具的射线检测
     * @param event 
     */
    onTouchStart(event: EventTouch) {
        const touch = event.touch!;
        this.camera.screenPointToRay(touch.getLocationX(), touch.getLocationY(), this._ray);
        if (PhysicsSystem.instance.raycast(this._ray)) {
            const raycastResults = PhysicsSystem.instance.raycastResults;
            for (let i = 0; i < raycastResults.length; i++) {
                const item = raycastResults[i];
                let clickPropIndex = this.propsForYou.findIndex(element => element == item.collider.node)
                if (clickPropIndex > -1) {
                    this.handleClickProps(clickPropIndex)
                }
            }
        } else {
        }
    }

    update(deltaTime: number) {
        // if (this.devil.position.z > -13) {
        //     this.devil.getChildByName("名字").active = true
        // } else {
        //     this.devil.getChildByName("名字").active = false
        // }
    }
    /**
     * 开始游戏
     */
    startGame() {
        this.menu.getChildByName("开始").active = false
        this.menu.getChildByName("结束").active = false
        const devilAnimation = this.devil.getComponent(Animation)
        this.animation.on(Animation.EventType.FINISHED, this.animationEnd, this)
        devilAnimation.play("devil")
        this.animation.play("cameraGo")
    }
    /**
     * 主相机动画结束事件
     * @param type 
     * @param state 
     */
    animationEnd(type: Animation.EventType, state: AnimationState) {
        switch (state.name) {
            case "cameraGo":
                this.gun.active = true
                // const rigidbody: RigidBody = this.gun.getComponent(RigidBody)
                setTimeout(() => {
                    this.showDialog()
                }, 1000)
                break;
            case "cameraBack":
                // this.menu.getChildByName("结束").active = false
                // this.menu.getChildByName("开始").active = true
                break;
            case "focusTable":
                if (this.animation.getState("focusTable").wrapMode == AnimationClip.WrapMode.Reverse) {
                    this.shootMenu.active = false
                } else {
                    this.shootMenu.active = true
                    // this.focusBullet()
                }
                break
            case "focusBullet":
                if (this.animation.getState("focusBullet").wrapMode == AnimationClip.WrapMode.Reverse) {
                    if (this.round > 1) {
                        this.addProps()

                    }
                    // this.unfocusedTable()
                } else {
                    setTimeout(() => {
                        this.unfocusBullet()
                    }, 500);
                }
                break

            default:
                break;
        }
    }
    /**
     * 展示情节对白对话框
     */
    showDialog() {
        // this.dialog.active = true
        this.dialog.showDialog()
    }
    /**
     * 情节对话框结束
     */
    dialogEnd() {
        if (this.bulletAry.length == 0) {
            this.bulletAry = this.bullet.createBullet(3)
            this.focusBullet()
        } else {

        }
        if (this.round == 0) {
            // this.addProps()
            this.blood.setInitBlood(3)
        }
    }
    /**
     * 把子弹数组随机打乱
     */
    randomBullet() {
        this.round++
        for (let i = this.bulletAry.length - 1; i > 0; i--) {
            // 生成一个随机数，用于交换元素
            const j = Math.floor(Math.random() * (i + 1));
            [this.bulletAry[i], this.bulletAry[j]] = [this.bulletAry[j], this.bulletAry[i]]; // 交换元素
        }
        console.log(this.bulletAry)

        setTimeout(() => {
            if (this.haveGun == "you") {
                this.focusTable()
            }
            else {
                this.scheduleOnce(() => {
                    this.aiShoot(0)
                }, 1)
            }
        }, 1000);
    }
    /**
     * 聚焦桌子动画 
     */
    focusTable() {
        let state = this.animation.getState("focusTable")
        state.wrapMode = AnimationClip.WrapMode.Normal
        this.animation.play("focusTable")
    }
    /**
     * 远离桌子动画
     */
    unfocusedTable() {
        let state = this.animation.getState("focusTable")
        state.wrapMode = AnimationClip.WrapMode.Reverse
        this.animation.play("focusTable")
    }
    /**
     * 聚焦子弹动画
     */
    focusBullet() {
        this.bullet.playAnimation(AnimationClip.WrapMode.Normal)
        let state = this.animation.getState("focusBullet")
        state.wrapMode = AnimationClip.WrapMode.Normal
        this.animation.play("focusBullet")
    }
    /**
     * 远离子弹动画
     */
    unfocusBullet() {
        this.bullet.playAnimation(AnimationClip.WrapMode.Reverse)
        let state = this.animation.getState("focusBullet")
        state.wrapMode = AnimationClip.WrapMode.Reverse
        this.animation.play("focusBullet")
    }
    /**
     * 射击事件
     * @param event 
     * @param obj 
     */
    handlerShoot(event: Event, obj: string) {
        this.dialog.hiddenDialog()
        this.shootMenu.active = false
        let gunRigibody: RigidBody = this.gun.getComponent(RigidBody)
        gunRigibody.useGravity = false
        if (this.haveGun == "you") {
            this.unfocusedTable()
        }
        let quat1: Vec3 = new Vec3()
        let quat2: Vec3 = new Vec3()
        if (obj == "you") {
            quat1 = new Vec3(0, 90, 0)
            quat2 = new Vec3(0, 90, -15)
        } else {
            quat1 = new Vec3(0, -90, 20)
            quat2 = new Vec3(0, -90, 5)
        }
        let particNode = this.gun.getChildByName("Particle")
        tween(this.gun)
            .to(1, {
                position: new Vec3(0, 0, 0), eulerAngles: quat1,
            })
            .delay(1)
            .call(() => {
                if (this.bulletAry[0]) {
                    particNode.active = true
                    // let particleSystem: ParticleSystem = particNode.getComponent(ParticleSystem)
                    // particleSystem.play()
                }
            })
            .to(0.1, { eulerAngles: quat2 })
            .call(() => {
                if (this.bulletAry[0] && obj == "ai") {
                    const devilAnimation = this.devil.getChildByPath("devil").getComponent(Animation)
                    devilAnimation.play("devil3")
                }
            })
            .to(0.5, { eulerAngles: quat1 })
            .union()
            .call(() => {
                gunRigibody.useGravity = true
            })
            .delay(2)
            .call(() => {
                particNode.active = false
                this.handleJudge(obj)
            })
            .start()

    }
    /**
     * 判断射击结果
     */
    handleJudge(obj: string) {
        let current = this.bulletAry.shift()

        if (current == 0 && this.haveGun == obj) {

        } else {
            if (current == 1) {
                if (!this.calculateResult(obj)) return
            } else[
            ]
            this.exchangeGun()
        }
        this.doubleDamage = false
        this.gun.getChildByName("doubleDamage").active = false
        this.nextRound()
    }
    /**
     * 计算血量
     */
    calculateResult(obj: string) {
        if (obj == "you") {
            let blood = this.blood.bloodLose()
            if (this.doubleDamage) {
                blood = this.blood.bloodLose()
            }
            if (blood <= 0) {
                this.gameOver("failed")
                return false
            }
        } else {
            if (this.devil.position.z < -13) {
                this.gameOver("success")
                return false
            } else {
            }
            if (this.doubleDamage) {

                this.repelNpc(2)
            } else {
                this.repelNpc(1)
            }
        }
        return true
    }
    /**
     * 交换当前枪的控制权
     *
     */
    exchangeGun() {
        if (this.stopRound) {
            this.stopRound = false
            if (this.haveGun == "you") {
                this.stopTag.getChildByName("stopdevil").active = false
            } else {
                this.stopTag.getChildByName("stopyou").active = false
            }
        } else {

            this.haveGun == "you" ? this.haveGun = "ai" : this.haveGun = "you"
        }
    }
    /**
     * 下一轮射击
     */
    nextRound() {
        if (this.bulletAry.length == 0) {
            // this.haveGun = "you"
            this.bulletAry = this.bullet.createBullet(Math.ceil(Math.random() * 4) + 3)
            this.focusBullet()
        } else {
            if (this.haveGun == "you") {
                this.focusTable()
            } else {
                this.scheduleOnce(() => {
                    this.aiShoot(0)
                }, 1)
            }
        }
    }
    /**
     * AI射击逻辑
     */
    aiShoot(index: number, selectFlg: any = { redflg: false, orangeflg: false, blueflg: false, greyflg: false }) {
        if (index == this.propsForNpc.length) {
            if (selectFlg.orangeflg && this.bulletAry[0]) {
                this.handlerShoot(null, "you")
            } else {
                this.handlerShoot(null, Math.random() > 0.5 ? "you" : "ai")
            }
            return
        } else {
            const element = this.propsForNpc[index];
            if (element) {
                let canTween = true
                switch (element.name) {
                    case "green":
                        this.handlerGreen()
                        break;
                    case "red":
                        if (!selectFlg.redflg) {
                            selectFlg.redflg = true
                            this.handlerRed()
                        } else {
                            canTween = false
                        }
                        break;
                    case "orange":
                        if (!selectFlg.orangeflg) {
                            selectFlg.orangeflg = true
                            this.dialog.setShowDialog("oh, so interesting...")
                        } else {
                            canTween = false

                        }
                        break;
                    case "blue":
                        if (!selectFlg.blueflg) {
                            selectFlg.blueflg = true
                            this.handlerBlue()
                        } else {
                            canTween = false

                        }

                        break;
                    case "grey":
                        if (!selectFlg.greyflg) {
                            selectFlg.greyflg = true
                            this.handlerGrey()
                        } else {
                            canTween = false

                        }
                        break;
                    default:
                        break;
                }
                if (canTween) {
                    this.deleteProps(index)
                    this.scheduleOnce(() => {
                        this.aiShoot(index + 1, selectFlg)
                        console.log(selectFlg)
                    }, 1)
                } else {
                    this.aiShoot(index + 1, selectFlg)
                }
            } else {
                this.aiShoot(index + 1, selectFlg)
            }
        }
    }

    /**
     * 游戏结束事件
     */
    gameOver(state: string) {
        let label: Label = this.menu.getChildByName("结束").getChildByName("Label").getComponent(Label)
        let message = this.menu.getChildByName("结束").getChildByName("message").getComponent(Label)
        if (state == "failed") {
            label.string = "很可惜，你没有击败你的梦魇"
        } else {
            label.string = "你成功击败了你的梦魇"
        }
        message.string = `你坚持了${this.round}回合`
        this.menu.getChildByName("结束").active = true
        this.animation.play("cameraBack")
        this.bulletAry = []
        this.round = 0
        this.blood.hideBloodUI()
        this.propsForNpc.fill(null)
        this.propsForYou.fill(null)
        this.propsNpcGroup.destroyAllChildren()
        this.propsYouGroup.destroyAllChildren()
    }

    /**
     * 击退梦魇npc
     */
    repelNpc(blood: number) {
        tween(this.devil)
            .to(0.5, {
                position: new Vec3(this.devil.position.x, this.devil.position.y, this.devil.position.z - blood),
            })
            .start()
    }

    /**
     * 生成道具节点
     */
    createPropNode(index: number) {
        let node = instantiate(this.prop)
        let random = Math.floor(Math.random() * 5)
        switch (random) {
            case 0:
                node.getComponent(ModelComponent).material = this.red
                node.name = "red"
                break;
            case 1:
                node.getComponent(ModelComponent).material = this.green
                node.name = "green"
                break;
            case 2:
                node.getComponent(ModelComponent).material = this.orange
                node.name = "orange"
                break;

            case 3:
                node.getComponent(ModelComponent).material = this.grey
                node.name = "grey"
                break;

            case 4:
                node.getComponent(ModelComponent).material = this.blue
                node.name = "blue"
                break;
            default:
                break;
        }
        // node.getComponent(ModelComponent).material = this.blue
        // node.name = "blue"
        node.position = new Vec3(this.postionAry[index].x, 0, this.postionAry[index].z)
        return node
    }
    /**
     * 添加道具
     */
    addProps() {
        let addNumberRandom = Math.ceil(Math.random() * 3)
        let ary = []
        for (let i = 0; i < addNumberRandom; i++) {
            let nullIndexForYou = this.propsForYou.map((elemetn, index) => { if (elemetn == null) return index }).filter(element => element != undefined)
            let nullIndexForNpc = this.propsForNpc.map((elemetn, index) => { if (elemetn == null) return index }).filter(element => element != undefined)
            let postionRandomForYou = Math.floor(Math.random() * nullIndexForYou.length)
            let postionRandomForNpc = Math.floor(Math.random() * nullIndexForNpc.length)
            if (nullIndexForYou.length > 0) {
                let youProp = this.createPropNode(nullIndexForYou[postionRandomForYou])
                youProp.parent = this.propsYouGroup
                this.propsForYou[nullIndexForYou[postionRandomForYou]] = youProp
                ary.push(youProp)
            }
            if (nullIndexForNpc.length > 0) {
                let npcProp = this.createPropNode(nullIndexForNpc[postionRandomForNpc])
                npcProp.parent = this.propsNpcGroup
                this.propsForNpc[nullIndexForNpc[postionRandomForNpc]] = npcProp
                ary.push(npcProp)
            }
        }
        for (let index = 0; index < ary.length; index++) {
            const element = ary[index];
            tween(element)
                .to(0.5, {
                    position: new Vec3(element.position.x, 0.15, element.position.z),

                })
                .start()
        }
    }

    /**
     * 点击道具
     */
    handleClickProps(index: number) {
        if (this.shootMenu.active == false) return
        this.dialog.hiddenDialog()
        let canTween = false
        switch (this.propsForYou[index].name) {
            case "red":
                if (this.doubleDamage) {
                    canTween = true
                } else {
                    this.handlerRed()
                }
                break;

            case "orange":
                this.handlerOrange()
                break;

            case "blue":
                this.handlerBlue()

                break;

            case "green":
                this.handlerGreen()

                break;

            case "grey":
                if (this.stopRound) {
                    canTween = true
                } else {
                    this.handlerGrey()
                }
                break;

            default:
                break;
        }
        if (!canTween) {
            this.deleteProps(index)
        }


    }
    /**
     * 删除道具
     */
    deleteProps(index: number) {
        let ary = this.haveGun == "you" ? this.propsForYou[index] : this.propsForNpc[index]
        console.log(ary, index, this.haveGun)
        tween(ary)
            .to(0.5, {
                position: new Vec3(ary.position.x, 0, ary.position.z),
            })
            .call(() => {
                ary.destroy()
                this.haveGun == "you" ? this.propsForYou[index] = null : this.propsForNpc[index] = null
            })
            .start()
    }
    /**
     * 双倍伤害
     */
    handlerRed() {
        this.doubleDamage = true
        this.gun.getChildByName("doubleDamage").active = true
    }
    /**
     * 查看下一发子弹
     */
    handlerOrange() {
        this.dialog.setShowDialog(`下一发是${this.bulletAry[0] ? "实弹" : "空弹"}`)
    }
    /**
     * 弹出下一发子弹
     */
    handlerBlue() {
        let bullet = instantiate(this.bulletPrefab)
        bullet.setPosition(new Vec3(this.gun.worldPosition.x, this.gun.worldPosition.y, this.gun.worldPosition.z))
        bullet.parent = this.node
        let meshrenderer = bullet.getComponent(MeshRenderer)
        if (this.bulletAry.shift() == 0) {
            meshrenderer.setSharedMaterial(this.bulletBlue, 0)
        } else {
            meshrenderer.setSharedMaterial(this.bulletRed, 0)
        }
        const rigidbody = bullet.addComponent(RigidBody)
        const boxCollider = bullet.addComponent(BoxCollider)
        boxCollider.isTrigger = true
        // rigidbody.applyForce(new Vec3(0, 200, 0))
        tween(bullet)
            .to(1, {
                position: new Vec3(bullet.position.x, 2.5, bullet.position.z)
            }, {
                easing: "sineOutIn"
            })
            .call(() => {

                this.node.removeAllChildren()
                if (this.bulletAry.length == 0) {
                    this.shootMenu.active = false
                    this.unfocusedTable()

                    this.scheduleOnce(() => {
                        this.nextRound()
                    }, 1)
                }
            })
            .start()
        // setTimeout(() => {
        //     this.node.removeAllChildren()
        // }, 1000)
        // if (this.bulletAry.length == 0) {
        //     setTimeout(() => {
        //         this.nextRound()
        //     }, 1000)
        //     this.shootMenu.active = false
        //     this.unfocusedTable()
        // }
    }
    /**
     * 回血
     */
    handlerGreen() {
        if (this.haveGun == "you") {
            this.blood.bloodReturn()
        } else {
            tween(this.devil)
                .to(0.5, {
                    position: new Vec3(this.devil.position.x, this.devil.position.y, Math.min(-2.8, this.devil.position.z + 1)),
                })
                .start()
        }
    }
    /**
     * 禁止一回合
     */
    handlerGrey() {
        this.stopRound = true
        if (this.haveGun == "you") {
            this.stopTag.getChildByName("stopdevil").active = true
        } else {
            this.stopTag.getChildByName("stopyou").active = true
        }
    }
}


